package com.tuo51.foudation.utils;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.annotations.NotFound;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import javax.persistence.Id;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;

public class CopyUtils {

	static Log log = LogFactory.getLog(CopyUtils.class);
	public static String[] getNullPropertyNames (Object source) {
		final BeanWrapper src = new BeanWrapperImpl(source);
		PropertyDescriptor[] pds = src.getPropertyDescriptors();

		Set<String> emptyNames = new HashSet<String>();
		for(PropertyDescriptor pd : pds) {
			Object srcValue = src.getPropertyValue(pd.getName());
			if (srcValue == null) emptyNames.add(pd.getName());
		}
		String[] result = new String[emptyNames.size()];
		return emptyNames.toArray(result);
	}

	public static void copyProperties(Object src, Object target) {
		BeanUtils.copyProperties(src, target);
	}

	public static void copyPropertiesWithoutNull(Object src, Object target) {
		BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
	}

	public static void copyNonullProperties(Object src, Object target) {
		//为空的属性值，忽略属性，BeanUtils复制的时候用到
		List<String> ignoreProperties = new ArrayList<String>();

		//获取最新数据，解决部分更新时jpa其他字段设置null问题
		try {
			//反射获取Class的属性（Field表示类中的成员变量）
			for (Field field : target.getClass().getDeclaredFields()) {
				//获取授权
				field.setAccessible(true);
				//属性名称
				String fieldName = field.getName();
				//属性的值
				Object fieldValue = field.get(src);

				//找出Id主键
				if (field.isAnnotationPresent(Id.class)) {
					//主键不要赋值
					ignoreProperties.add(fieldName);
				}
				//如果前端不传这两个值，后台来维护创建时间、更新时间
				if( "updated".equals(fieldName) || "updateTime".equals(fieldName) ){
					//set方法，第一个参数是对象
					field.set(target, new Date());
				}

				//找出值为空的属性，值为空则为忽略属性，或者被NotFound标注，我们复制的时候不进行赋值
				if(null == fieldValue || field.isAnnotationPresent(NotFound.class)){
					ignoreProperties.add(fieldName);
				}
			}
            /*
                org.springframework.beans BeanUtils.copyProperties(A,B); 是A中的值付给B
                org.apache.commons.beanutils; BeanUtils.copyProperties(A,B);是B中的值付给A
                把entity的值赋给entityFull，第三个参数是忽略属性，表示不进行赋值
             */
			BeanUtils.copyProperties(src, target, ignoreProperties.toArray(new String[0]));
		} catch (IllegalAccessException e) {
			//输出到日志文件中
			log.error(e);
		}
	}

	public static < S,T> void copyListProperties(List<S> srcList, List<T> targetList,Class<T> targetClass) throws InstantiationException, IllegalAccessException  {
		if(CollectionUtils.isEmpty(srcList) ){
			return ;
		}
		for(S s:srcList){
			T target=targetClass.newInstance();
			BeanUtils.copyProperties(s, target, getNullPropertyNames(s));
			targetList.add(target);
		}
	}




	/**
	 * bean to map
	 * @param obj
	 * @return
	 */
	public static Map<String, Object> transBean2Map(Object obj) {
		if(obj == null){
			return null;
		}
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			for (PropertyDescriptor property : propertyDescriptors) {
				String key = property.getName();

				// 过滤class属性
				if (!key.equals("class") && !key.equals("hibernateLazyInitializer")) {
					// 得到property对应的getter方法
					Method getter = property.getReadMethod();
					Object value = getter.invoke(obj);

					map.put(key, value);
				}

			}
		} catch (Exception e) {
			log.error("transBean2Map Error " ,e);
		}
		return map;
	}


	public static void transMap2Bean(Map<String, Object> map, Object obj) {

		try {
			BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

			for (PropertyDescriptor property : propertyDescriptors) {
				String key = property.getName();

				if (map.containsKey(key)) {
					Object value = map.get(key);
					// 得到property对应的setter方法
					Method setter = property.getWriteMethod();
					setter.invoke(obj, value);
				}

			}

		} catch (Exception e) {
			System.out.println("transMap2Bean Error " + e);
		}

		return;

	}

}

